﻿using AutoMapper;
using DFGK.IRepository;
using DFGK.IService;
using DFGK_WMS.Model.Dto;
using DFGK_WMS.Model.Enum;
using DFGK_WMS.Model.Exports;
using DFGK_WMS.Model.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace DFGK.Service
{
    public class InventoryService : BaseService, IInventoryService
    {
        private readonly IInventoryRepository _inventoryRepository;
        private readonly IPalletRepository _palletRepository;
        private readonly IMaterialRepository _materialRepository;
        private readonly IInventoryLogRepository _inventoryLogRepository;
        public InventoryService(IMapper mapper, IInventoryRepository inventoryRepository, IMaterialRepository materialRepository, IPalletRepository palletRepository, IInventoryLogRepository _inventoryLogRepository) : base(mapper)
        {
            _inventoryRepository = inventoryRepository;
            _materialRepository = materialRepository;
            _palletRepository = palletRepository;
            this._inventoryLogRepository = _inventoryLogRepository;
        }

        public Inventory? GetInventoryByCellCode(string code)
        {
            return _inventoryRepository.QueryIsEntityWhere(x => x.LocationCode == code);
        }

        public List<Inventory> GetInventoryDetailList(long whId, string? mname, int status, string? locationcode, int pageIndex, int pageSize, out int totalCount)
        {
            var list = _inventoryRepository.GetEntityAlls();
            if (whId != 0)
                list = list.Where(x => x.AreaId == whId);

            if (!string.IsNullOrEmpty(mname))
                list = list.Where(x => x.MaterialCode.Contains(mname) || x.MaterialName.Contains(mname));

            if (status != 0)
                list = list.Where(x => x.Status == status);
            if (!string.IsNullOrEmpty(locationcode))
                list = list.Where(x => x.LocationCode.Contains(locationcode));

            var lists = _inventoryRepository.GetEntityAlls(list, pageIndex, pageSize, out totalCount, x => x.CreateDate, false);
            return lists.ToList();
        }

        public List<InventoryExport>? GetInventoryExport(int status)
        {
            var list = _inventoryRepository.GetEntityAlls();
            if (status != 0)
                list = list.Where(x => x.Status == status);
            List<InventoryExport> inventoryExports = new List<InventoryExport>();
            if (list.Any())
            {
                foreach (var item in list)
                {
                    InventoryExport inventoryExport = new InventoryExport();
                    inventoryExport = mapper.Map<InventoryExport>(item);
                    if (item.Status == 1)
                        inventoryExport.Status = "正常库存";
                    else if (item.Status == 2)
                        inventoryExport.Status = "转移中的库存";
                    else if (item.Status == 3)
                        inventoryExport.Status = "入库在途";
                    else if (item.Status == 4)
                        inventoryExport.Status = "出库在途";
                    else if (item.Status == 5)
                        inventoryExport.Status = "限制使用的库存";
                    else if (item.Status == 6)
                        inventoryExport.Status = "异常库存";
                    else if (item.Status == 7)
                        inventoryExport.Status = "预分配库存";
                    else if (item.Status == 8)
                        inventoryExport.Status = "冻结库存";

                    inventoryExports.Add(inventoryExport);
                }
                return inventoryExports;
            }
            return null;
        }

        public List<Inventory> GetInventoryMsgDown()
        {
            var list = _inventoryRepository.GetAllEntityList();
            return list;
        }

        public List<DefectiveProductsDto>? GetDefectiveProducts()
        {
            List<DefectiveProductsDto> defectiveProductsDtos = new List<DefectiveProductsDto>();
            var list = _inventoryRepository.GetEntityWhereAll(x => x.QualityState == 2).ToList();
            foreach (var item in list)
            {
                DefectiveProductsDto dto = new DefectiveProductsDto();
                dto.MaterialCode = item.MaterialCode;
                dto.MaterialName = item.MaterialName;
                dto.CellCode = item.LocationCode;
                dto.Qty = item.AvailableQty == 0 ? 0 : (decimal)item.AvailableQty;
                var inventoryLog = _inventoryLogRepository.GetEntityWhereAll(x => x.MaterialCode == item.MaterialCode).LastOrDefault();
                if (inventoryLog.SourceType == 0)
                {
                    dto.SourceType = 1;
                }
                else if (inventoryLog.SourceType == 1)
                {
                    dto.SourceType = 2;
                }
                dto.UpdQty = inventoryLog.ChangeQty == 0 ? 0 : (decimal)inventoryLog.ChangeQty;
                defectiveProductsDtos.Add(dto);
            }
            return defectiveProductsDtos;
        }

        public List<Inventory> GetInventoryGroupList(long whId, string? mname, int pageIndex, int pageSize, out int totalCount)
        {
            var list = _inventoryRepository.GetEntityAlls();

            if (whId != 0)
                list = list.Where(x => x.WarehouseId == whId);

            if (!string.IsNullOrEmpty(mname))
                list = list.Where(x => x.MaterialCode.Contains(mname) || x.MaterialName.Contains(mname));

            var res = list
                        .GroupBy(s => s.MaterialId)
                        .Select(g => new Inventory()
                        {
                            Id = g.First().Id,
                            MaterialCode = g.First().MaterialCode,
                            MaterialName = g.First().MaterialName,
                            AvailableQty = (int)g.Sum(s => s.AvailableQty).GetValueOrDefault(),
                            CreateDate = g.First().CreateDate,
                        })
                        .OrderByDescending(x => x.CreateDate);
            var lists = _inventoryRepository.GetEntityAlls(res, pageIndex, pageSize, out totalCount, x => x.CreateDate, false);
            return lists.ToList();
        }

        public List<InventoryPalletDto> GetInventoryPalletDto(string key, int pageIndex, int pageSize, out int totalCount)
        {
            var ilist = _inventoryRepository.GetEntityWhereAll(x => x.Status == 1 && x.IsLock == false || (x.Status == 5 && x.IsLock == true));

            if (!string.IsNullOrEmpty(key))
                ilist = ilist.Where(x => x.MaterialCode.Contains(key));

            var plist = _palletRepository.GetEntityWhereAll(x => x.Status == 1);

            var list = from a in ilist
                       join b in plist
                       on a.PalletBarcode equals b.PalletBarcode
                       select new InventoryPalletDto
                       {
                           Id = a.Id,
                           MaterialCode = a.MaterialCode,
                           MaterialId = a.MaterialId,
                           MaterialName = a.MaterialName,
                           BatchNo = a.BatchNo,
                           AvailableQty = a.AvailableQty,
                           LoadFactor = b.LoadFactor,
                           PalletBarcode = a.PalletBarcode,
                           LocationCode = a.LocationCode,
                       };
            totalCount = list.Count();
            return list.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
        }

        public List<InventoryWarn> GetInventoryWarnList(int type, long wid, long aid, int pageIndex, int pageSize, out int totalCount)
        {
            var mlist = _materialRepository.GetEntityAlls();
            var ilist = _inventoryRepository.GetEntityAlls();

            if (wid > 0)
                ilist = ilist.Where(x => x.WarehouseId == wid);
            if (aid > 0)
                ilist = ilist.Where(x => x.AreaId == aid);
            List<InventoryWarn> iwlist = new List<InventoryWarn>();
            decimal? availableQty = 0;
            int? maxsafetystock = 0;
            int? minsafetystock = 0;
            foreach (var item in ilist.ToList())
            {
                InventoryWarn ilobj = new InventoryWarn();
                availableQty = item.AvailableQty;
                maxsafetystock = mlist.FirstOrDefault(x => x.Id == item.MaterialId)?.MaxSafetyStock;
                minsafetystock = mlist.FirstOrDefault(x => x.Id == item.MaterialId)?.MinSafetyStock;
                if (item.ExpireDate != null)
                {
                    if (item.CreateDate > item.ExpireDate)
                    {
                        ilobj = mapper.Map<InventoryWarn>(item);
                        ilobj.MaxSafetyStock = maxsafetystock;
                        ilobj.MinSafetyStock = minsafetystock;
                        ilobj.QTY = availableQty;
                        ilobj.WarnType = 3;
                        ilobj.WhId = item.WarehouseId;
                        ilobj.WhName = item.WarehouseName;
                        if (type > 0 && type == 3)
                            iwlist.Add(ilobj);
                        else if (type == 0)
                            iwlist.Add(ilobj);
                    }
                }
                else if (availableQty < minsafetystock)
                {
                    ilobj = mapper.Map<InventoryWarn>(item);
                    ilobj.MaxSafetyStock = maxsafetystock;
                    ilobj.MinSafetyStock = minsafetystock;
                    ilobj.QTY = availableQty;
                    ilobj.WarnType = 1;
                    ilobj.WhId = item.WarehouseId;
                    ilobj.WhName = item.WarehouseName;
                    if (type > 0 && type == 1)
                        iwlist.Add(ilobj);
                    else if (type == 0)
                        iwlist.Add(ilobj);
                }
                else if (availableQty > maxsafetystock)
                {
                    ilobj = mapper.Map<InventoryWarn>(item);
                    ilobj.MaxSafetyStock = maxsafetystock;
                    ilobj.MinSafetyStock = minsafetystock;
                    ilobj.QTY = availableQty;
                    ilobj.WarnType = 2;
                    ilobj.WhId = item.WarehouseId;
                    ilobj.WhName = item.WarehouseName;
                    if (type > 0 && type == 2)
                        iwlist.Add(ilobj);
                    else if (type == 0)
                        iwlist.Add(ilobj);
                }
            }
            totalCount = iwlist.Count;
            return iwlist;
        }


        /// <summary>
        /// 不良品库存查询
        /// </summary>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="totalCount"></param>
        /// <returns></returns>
        public List<Inventory> GetDefectiveProducts(int pageIndex, int pageSize, out int totalCount)
        {
            var inventoryList = _inventoryRepository.GetEntityWhereAll(x => x.QualityState == 2);
            totalCount = inventoryList.Count();
            return inventoryList.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
        }


        public List<object> GetInventroyIn()
        {
            var inventoryList = _inventoryRepository.GetEntityAll().Where(t => t.BusinessType == (int)EmBusinessType.In).ToList();
            var inventoryGroup = inventoryList.GroupBy(t => new { t.LocationCode, t.LocationName });
            List<object> list = new List<object>();
            foreach (var itemGroup in inventoryGroup)
            {
                list.Add(new
                {
                    itemGroup.Key.LocationName,
                    itemGroup.Key.LocationCode,
                    MaterialInfo = itemGroup.Select(t => new { t.MaterialCode, t.MaterialName, t.CreateDate, t.LocationName }).ToList(),

                });
            }
            return list;


        }


        public List<Inventory> GetInventoryStockeCell(int pageIndex, int pageSize, out int totalCount)
        {
            totalCount = 0;

            var query = _inventoryRepository.GetEntityAll();
            totalCount = query.Count();
            return query
            .OrderBy(t => t.LocationLineNo)
            .OrderBy(t => t.LocationLayerNo)
            .OrderBy(t => t.LocationColumnNo)
            .Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
        }

    }
}
